Luogu P3936 Coloring题解

这道题……作为退火的练习题非常毒瘤,因为这个参是真的不好调。

但最后终于还是切掉了,于是非常的高兴,决定写个题解纪念一下QwQ

这道题退火的思路似乎还是挺好想的,每次退火随机出一个染色方案,然后在降温过程中每次随机的交换两个色块,如果更优则接受,更新答案,反之则以一定概率接受,多次进行直到找到最优解为止。然后调一调参就A掉了(然而调参调的精分了QwQ

以下是代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <bits/stdc++.h>
#define ri register int
#define il inline
#define ll long long
#define sqr(x) ((x)*(x))
using namespace std;
const int N=100000+110;
const int inf=0x7fffffff;
const int MAXN=110;
const double eps=1e-15;
const double deltaT=0.999911;
il int read()
{
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(isdigit(ch))
{
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
return x*f;
}
int n,m,c,ans=inf;
int E[MAXN],p[MAXN];
int C[MAXN][MAXN],put[MAXN][MAXN];
double Rand()
{
return 1.0*(rand()%100000000)/100000000;
}
il void update(int x)
{
if(x>=ans)
return;
ans=x;
for(ri i=1;i<=n;i++)
for(ri j=1;j<=m;j++)
put[i][j]=C[i][j];
}
il int get_num(int x,int y)
{
int ret=0;
if(C[x][y]!=C[x][y-1])
ret++;
if(C[x][y]!=C[x][y+1])
ret++;
if(C[x][y]!=C[x-1][y])
ret++;
if(C[x][y]!=C[x+1][y])
ret++;
return ret;
}
il void SimulatedAnneal()
{
double T=24101632;
for(ri i=1;i<=c;i++)
E[i]=p[i];
for(ri i=1;i<=n;i++)
for(ri j=1;j<=m;j++)
{
int colour=1+rand()%c;
while(!E[colour])
colour=1+rand()%c;
C[i][j]=colour,E[colour]--;
}
int now=0;
for(ri i=1;i<=n;i++)
for(ri j=1;j<=m;j++)
now+=get_num(i,j);
while(T>eps)
{
int x1=1+rand()%n,y1=1+rand()%m;
int x2=1+rand()%n,y2=1+rand()%m;
int pre=now;
now-=(get_num(x1,y1)+get_num(x2,y2));
swap(C[x1][y1],C[x2][y2]);
now+=(get_num(x1,y1)+get_num(x2,y2));
if(now<pre||exp((pre-now)/T)>Rand())
update(now);
else
now=pre,swap(C[x1][y1],C[x2][y2]);
T*=deltaT;
}
}
int main()
{
srand((unsigned)time(NULL));
n=read(),m=read(),c=read();
for(ri i=1;i<=c;i++)
p[i]=read();
for(ri i=1;i<=50;i++)
SimulatedAnneal();
for(ri i=1;i<=n;i++)
{
for(ri j=1;j<=m;j++)
printf("%d ",put[i][j]);
printf("\n");
}
return 0;
}

很奇怪的就是不开O2优化会RE,我也不知道为什么,反正过了就过了(雾

0%